/** 
 * @include "./lib/jquery.rotate.js"
 */

;(function( $ ){
	if ( ! $  ){
		/* No life without jQuery */
		return;
		}
	var
		BROWSER = window.BROWSER
			? window.BROWSER
			: {
				isIE: /*@cc_on!@*/false,
				isOpera:!!(window.opera && opera.version)
				},
		ClockController = (function(){
			var
				_settings = {
					featureActiveClass : 'clock-nav-active',
					animDuration : 500,
					handShadowOffsetLeft : -8,
					hourHandUpdateInterval : 30000,
					nextFeatureInterval : 2000,
					staticFallbackClass : 'clock-static-disabled'
					},
				/** @type {jQuery} */
				$clock,
				/** @type {jQuery} */
				$nav,
				/** @type {jQuery} */
				$features,
				/** @type {jQuery} */
				$hourHand,
				/** @type {jQuery} */
				$hourHandShadow,
				/** @type {jQuery} */
				$minuteHand,
				/** @type {jQuery} */
				$minuteHandShadow,
				/** @type {Boolean} */
				isOnFeature = false,
				/** @type {Number} */
				featuresLength = 6,
				/** @type {Number} */
				featureAngleStep = 60,
				/** @type {Number} */
				activeFeatureAngle = 0,
				/** @type {Number} */
				nextFeatureTimer;
			
			/** 
			 * Calculates the angle corresponding to given feature num
			 * @param {Number}
			 */
			function num2angle( num ){
				return ( num - 1 ) * featureAngleStep - 90;
				}
				
			/** 
			 * Calculates the feature num corresponding to given angle
			 * @param {Number}
			 */
			function angle2num( angle ){
				return ( ( angle % 360 + 90 ) / featureAngleStep ) % featuresLength + 1;
				}
			
			/** 
			 * Makes shadow of clock hand visible correct for given angle
			 * @param {String} type of clock hand: <code>hour</code> or <code>minute</code>
			 * @param {Number}
			 */
			function actualizeClockHand( type , angle ){
				var
					/** @type {DOMElement} */
					shadow; 
				if ( ! $.isNativeRotateSupported ){
					return;
					}
				angle = angle % 360;
				if ( type === 'hour' ){
					/* Hour clock hand */
					shadow = $hourHandShadow[0];
					}
				else{
					/* Minute clock hand */
					shadow = $minuteHandShadow[0];
					}
					
				if ( angle > 0 && angle < 180 ){
					shadow.style.marginLeft = [ 3 + _settings.handShadowOffsetLeft, 'px' ].join('');
					}
				else{
					shadow.style.marginLeft  = [ - 5 + _settings.handShadowOffsetLeft, 'px' ].join('');
					}
					
				if ( 
					( angle >= -60 && angle <= 60 )
					|| ( angle >= 300 && angle <= 420 )
					){
					shadow.style.marginTop  = '6px';
					}
				else if ( angle >= 120 && angle <= 240 ){
					shadow.style.marginTop  = '-8px';
					}
				else{
					shadow.style.marginTop  = '0';
					}
				}
				
			/** 
			 * Places the hour hand according to the current time
			 */
			function placeHourHand(){
				var 
					dt = new Date(),
					hours = dt.getHours() % 12 + dt.getMinutes() / 60,
					angle = hours * 30 - 90;
				$hourHand.rotate( angle )
				actualizeClockHand( 'hour' , angle );
				return placeHourHand;
				}
				
			/** 
			 * Clears next-feature-switch timer
			 */
			function resetNextFeatureTimer(){
				if ( nextFeatureTimer ){
					clearTimeout( nextFeatureTimer );
					nextFeatureTimer = undefined;
					}
				}
				
			/** 
			 * Sets timer and when it done activates next feature 
			 */
			function nextFeature(){
				resetNextFeatureTimer();
				nextFeatureTimer = setTimeout(function(){
					if ( FLRT.dialogs && FLRT.dialogs.inviteConfirm && FLRT.dialogs.inviteConfirm.active ){
						nextFeature();
						return;
						}
					if ( isOnFeature ){
						nextFeature();
						}
					else{
						activateFeature( 
							$features.eq( angle2num( activeFeatureAngle ) % featuresLength ),
							nextFeature
							)
						}
					}, _settings.nextFeatureInterval )
				}
				
			/** 
			 * Makes active feature specified by given container
			 * @param {jQuery} $feature container of feature which need to be activated
			 * @param {Function} complete callback to run when rotate animation is complete
			 */
			function activateFeature( $feature , complete ){
				var
					/** @type {Number} */
					num = Number( + $feature.attr( 'id' ).split( '' ).pop() ),
					/** @type {Number} */
					prevNum = angle2num( activeFeatureAngle ),
					diffNum = num - prevNum,
					/** @type {Number} */
					angle,
				isOnFeature = true;
				if ( prevNum == num ){
					/* Has activated early */
					return;
					}
				if ( 
					(  num > prevNum && ( num - prevNum <= ( featuresLength / 2 )  ) ) || 
					( num < prevNum && ( num + featuresLength - prevNum <= ( featuresLength / 2 ) ) )
					){
					if ( diffNum < 0 ){
						diffNum += featuresLength;
						}
					}
				else if ( diffNum > 0 ){
					diffNum -= featuresLength;
					}
				
				angle = activeFeatureAngle + diffNum * featureAngleStep;
				activeFeatureAngle = angle;
				$features.removeClass( _settings.featureActiveClass );
				$feature.addClass( _settings.featureActiveClass );
				$minuteHand.rotate( {
					animateTo: angle,
					duration : _settings.animDuration,
					callback : function(){
						/* Reseting */
						if ( activeFeatureAngle >= 270 ){
							$minuteHand.rotate( activeFeatureAngle = activeFeatureAngle % 360 );
							}
						else if ( activeFeatureAngle < -90 ){
							$minuteHand.rotate( activeFeatureAngle = 360 + activeFeatureAngle % 360 );
							}
						actualizeClockHand( 'minute' , activeFeatureAngle );
						complete && complete();
						},
					step : function( ang ){
						actualizeClockHand( 'minute' , ang );
						}
					} );
				}
				
				
			return {
				/** 
				 * Initializes controller. Has to be run at once.
				 * Finds all needed containers, binds events, starts timers etc
				 */
				init : function(){
					$clock = $( '#clock' );
					if ( ! $clock.length ){
						/* Cannot continue without clock container on the page */
						return;
						}
					if ( BROWSER.isOpera && ! $.isNativeRotateSupported ){
						/* Falling back to static pic */
						$clock.addClass( _settings.staticFallbackClass );
						return;
						}
					$nav = $( '#clock-nav' );
					$features = $nav.find( '>li' )
						.mouseover(function(/* Event */e){
							activateFeature( $( this ) );
							resetNextFeatureTimer();
							})
						.mouseout(function(){
							isOnFeature = false;
							nextFeature();
							})
							
					$features.find( 'a' ).click(function(){
						if ( window.AccountController ){
							window.AccountController.switchPanel( 'signup' );
							}
						return false;
						})
					featuresLength = $features.length;
					featureAngleStep = 360 / featuresLength;
					activeFeatureAngle = num2angle( 1 ); 
					
					if ( BROWSER.isIE && ! $.isNativeRotateSupported ){
						$( '#clock-hand-hour' ).remove();
						$( '#clock-hand-minute' ).remove();
						$hourHand = $( '<img src="/static/images/v2/clock_hour_hand.png" id="clock-hand-hour-img" class="clock-hand" />' )
							.appendTo( $clock );
						$minuteHand = $( '<img src="/static/images/v2/clock_minute_hand.png" id="clock-hand-minute-img" class="clock-hand" />' )
							.appendTo( $clock );
						}
					else{
						$hourHand = $( '#clock-hand-hour' );
						$hourHandShadow = $hourHand.find( '>.clock-hand-shadow' );
						
						$minuteHand = $( '#clock-hand-minute' );
						$minuteHandShadow = $minuteHand.find( '>.clock-hand-shadow' );
						}
						
					/* Start */
					activateFeature( $features.eq( 1 ) );
					setInterval( placeHourHand() , _settings.hourHandUpdateInterval );
					nextFeature();
					}
				}
			})(),
		
		LiveNumber = function( options ){
			var
				_options = {
					},
				/** @type {jQuery} */
				$container,
				/** @type {Number} */
				num,
				/** @type {Number} */
				prevNum,
				/** @type {Digit()[]} */
				digits = [],
				/** 
				 * Public of LiveNumber()
				 */
				instance = {
					setOptions : function( o ){
						$.extend( _options , o );
						if ( _options.container ){
							this.setContainer( _options.container );
							delete _options.container;
							}
						},
					setContainer : function( cnt ){
						$container = $( cnt );
						},
					setNumber : function( n ){
						if ( isNaN( num ) ) {
							this.replaceNumber( n );
							}
						else {
							this.increase( n - num );
							}
						},
					replaceNumber : function( n ){
						num = n;
						render();
						},
					increase : function( diff ){
						if ( diff > 0 && digits[ 0 ] ) {
							digits[ 0 ].increase( diff );
							prevNum = num;
							num += diff;
							}
						}
					}
			options && instance.setOptions( options );
			
			/** 
			 * Renders initial
			 */
			function render(){
				var
					d = num.toString().split( '' );
				digits = [];
				$container.empty();
				for ( var i = d.length - 1 ; i >= 0; i-- ) {
					Digit({ digit : Number( d[ i ] ) });
					}
				}
				
			function Digit( digitOptions ){
				var
					_dOptions = {
						parent      : undefined,
						stepDelay   : 50,
						frameDelay  : 80
						},
					/** @type {jQuery} */
					$dContainer,
					/** @type {jQuery} */
					$digit,
					/** @type {Number} */
					digit,
					/** @type {Number} */
					pos = 0,
					/** @type {Number} */
					prevDigit,
					/** 
					 * Public of Digit()
					 */
					_digitInstance = {
						setOptions : function( o ){
							$.extend( _dOptions , o );
							if ( ! isNaN( _dOptions.digit ) ){
								var parentIncrease;
								digit = _dOptions.digit;
								delete _dOptions.digit;
								}
							},
						increase : function( diff , opt ){
							if ( ! $dContainer ){
								/* Not initialized yet */
								return;
								}
							var 
								_opt = {
									animate   : true,
									complete  : function(){}
									},
								currValue = digit,
								newValue,
								parentIncrease,
								stepNum = 0;
							opt && $.extend( _opt , opt );
							if ( diff < 0 ){
								/* Error: new digit cannot be less than previous */
								return;
								}
							newValue = digit + diff;
							parentIncrease = Math.floor( newValue  / 10 )
							function step(){
								currValue ++;
								if ( currValue == 10 ){
									currValue = 0;
									newValue = newValue % 10;
									}
								displayDigit( currValue , function(){
									if ( currValue < newValue && stepNum ++ < 50 ){
										setTimeout( step , _dOptions.stepDelay )
										}
									} );
								}
							if ( parentIncrease ){
								if ( _dOptions.parent ){
									_dOptions.parent.increase( parentIncrease );
									}
								else{
									Digit({
										digit   : parentIncrease
										});
									}
								}
							step();
							prevDigit = digit;
							digit = ( digit + diff ) % 10;
							},
						getContainer : function(){
							return $dContainer;
							},
						render : function(){
							var parentIncrease = Math.floor( digit / 10 );
							if ( ! $dContainer ){
								$dContainer = $( j( 
									'<span class="n_people_cnt_item">' ,
										'<span class="n_people_foot" />',
									'</span>'
									) );
								$digit = $( '<span class="n_people_o" />' ).prependTo( $dContainer );
								if ( pos && ! ( pos % 3 ) ){
									$( j( 
										'<span class="n_people_cnt_item n_people_space">',
											'<span class="n_people_os" />',
										'</span>'
										) ).prependTo( $container );
									}
								$dContainer.prependTo( $container );
								}
							if ( parentIncrease ){
								if ( _dOptions.parent ){
									_dOptions.parent.increase( parentIncrease );
									}
								else{
									Digit({
										digit   : parentIncrease
										});
									}
								digit = digit % 10;
								}
							displayDigit( digit );
							}
						};
						
				function displayDigit( d , complete ){
					if ( complete ){
						$dContainer.attr( 'class' , j( 'n_people_cnt_item ' , 'n_people_item_pos_to_' , d , '_1'  ) );
						setTimeout(function(){
							$dContainer.attr( 'class' , j( 'n_people_cnt_item ' , 'n_people_item_pos_to_' , d , '_2'  ) );
							setTimeout(function(){
								displayDigit( d );
								complete();
								} , _dOptions.frameDelay);
							}, _dOptions.frameDelay );
						}
					else{
						$dContainer.attr( 'class' , j( 'n_people_cnt_item ' , 'n_people_item_pos_' , d ) );
						$digit.text( d );
						}
					}
				
				digitOptions && _digitInstance.setOptions( digitOptions );
				
				pos = digits.length;
				digits.push( _digitInstance );
				if ( pos > 0 ){
					digits[ pos - 1 ].setOptions({
						parent : _digitInstance
						})
					}
				_digitInstance.render();
				return _digitInstance;
				}
			
			return instance;
			};

	/**
	 * Fire!
	 */
	$(function() {
		ClockController.init();

		(function() {
			var
				$regNum = $('#index-reg-num'),
				num = parseInt(strip_tags($regNum.html()).replace(/[^0-9]+/g, '')) || 0,
				dlt = parseInt($regNum.data('dlt')),
				rn = LiveNumber({
					container: $regNum
				}),
				minInterval = 0,
				maxInterval = 0,
				minStep = 1,
				maxStep = 1,
				avg = 0;
			rn.setNumber(num);

			if (dlt) {
				avg = parseInt(3600000 / dlt);

				while (avg < 1100) {
					avg = avg * 2;
					maxStep += 2;
				}
				minInterval = avg - 1000;
				maxInterval = avg + 1000;

				var rand = function(min, max) {    // Generate a random integer
					// +   original by: Leslie Hoare
					if (max) {
						return Math.floor(Math.random() * (max - min + 1)) + min;
					} else {
						return Math.floor(Math.random() * (min + 1));
					}
				};
				var step = function() {
					num += rand(minStep, maxStep);
					rn.setNumber(num);
					setTimeout(step, rand(minInterval, maxInterval));
				};
				setTimeout(step, rand(minInterval, maxInterval));

			}

		})();
	});

})( window.jQuery );
